package com.sniper.util;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author suzhen
 */
public class DataUtil {

    public static String md5(File file) {
        InputStream is;
        try {
            is = new FileInputStream(file);
            return DigestUtils.md5Hex(is);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "";
    }

    public static String md5(String md5) {
        String result = "";
        try {
            StringBuilder buffer = new StringBuilder();
            char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                    'A', 'B', 'C', 'D', 'E', 'F'};
            byte[] bytes = md5.getBytes();
            MessageDigest digest = MessageDigest.getInstance("MD5");
            byte[] bs = digest.digest(bytes);
            for (byte b : bs) {
                buffer.append(chars[(b >> 4) & 0x0F]);
                buffer.append(chars[b & 0x0F]);
            }
            result = buffer.toString().toLowerCase();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 从str中随机读取 num 个字符串
     *
     * @param str
     * @param num
     * @return
     */
    public static String getStringRandom(String str, int num) {

        if (!StringUtils.isNotBlank(str)) {
            return "";
        }
        Random random = new Random();
        StringBuilder cs = new StringBuilder();
        int strLength = str.length();
        int a = 0;
        for (int i = 0; i < num; i++) {
            a = random.nextInt(strLength - 1);
            cs.append(str.substring(a, a + 1));
        }
        return cs.toString();

    }

    /**
     * 首字母转小写
     *
     * @param s
     * @return
     */
    public static String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder())
                    .append(Character.toLowerCase(s.charAt(0)))
                    .append(s.substring(1)).toString();
        }

    }

    /**
     * 首字母转大写
     *
     * @param s
     * @return
     */
    public static String toUpperCaseFirstOne(String s) {
        if (Character.isUpperCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder())
                    .append(Character.toUpperCase(s.charAt(0)))
                    .append(s.substring(1)).toString();
        }

    }

    /**
     * 深度复制序列化
     *
     * @param src
     * @return
     */
    public static Serializable deeplyCopy(Serializable src) {

        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(outputStream);
            oos.writeObject(src);
            oos.close();
            outputStream.close();

            byte[] bytes = outputStream.toByteArray();
            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(inputStream);
            Serializable copy = (Serializable) ois.readObject();
            inputStream.close();
            ois.close();
            return copy;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return src;

    }

    /**
     * 对象转成byte
     *
     * @param object
     * @return
     */
    public static byte[] serialize(Object object) {
        ObjectOutputStream oos;
        ByteArrayOutputStream baos;
        try {
            // 序列化
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Object unSerialize(byte[] bytes) {
        ByteArrayInputStream bais = null;
        try {
            // 反序列化
            bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 1.用了3秒
     *
     * @param str <a href="http://my.oschina.net/u/556800" class="referer"
     *            target="_blank">@return</a>
     */
    public static String firstLetterToUpper(String str) {
        char[] array = str.toCharArray();
        array[0] -= 32;
        return String.valueOf(array);
    }

    /**
     * 2.用了5秒
     *
     * @param str <a href="http://my.oschina.net/u/556800" class="referer"
     *            target="_blank">@return</a>
     */
    public static String lcyFirstLetterToupper(String str) {
        return String.valueOf(str.charAt(0)).concat(str.substring(1));
    }

    /**
     * 3.用了5秒
     *
     * @param str <a href="http://my.oschina.net/u/556800" class="referer"
     *            target="_blank">@return</a>
     */
    public static String letterToUpper(String str) {
        Character c = Character.toUpperCase(str.charAt(0));
        return c.toString().concat(str.substring(1));
    }

    /**
     * 将Unicode字符串转换成bool型数组
     *
     * @param input
     * @return
     */
    public boolean[] strToBool(String input) {
        return binstr16ToBool(binstrToBinstr16(strToBinstr(input)));
    }

    /**
     * 将bool型数组转换成Unicode字符串
     *
     * @param input
     * @return
     */
    public String boolToStr(boolean[] input) {
        return binstrToStr(binstr16ToBinstr(boolToBinstr16(input)));
    }

    /**
     * 将字符串转换成二进制字符串，以空格相隔
     *
     * @param str
     * @return
     */
    private String strToBinstr(String str) {
        char[] strChar = str.toCharArray();
        StringBuilder result = new StringBuilder();
        for (char aStrChar : strChar) {
            result.append(Integer.toBinaryString(aStrChar)).append(" ");
        }
        return result.toString();
    }

    /**
     * 将二进制字符串转换成Unicode字符串
     *
     * @param binStr
     * @return
     */
    private String binstrToStr(String binStr) {
        String[] tempStr = strToStrArray(binStr);
        char[] tempChar = new char[tempStr.length];
        for (int i = 0; i < tempStr.length; i++) {
            tempChar[i] = binstrToChar(tempStr[i]);
        }
        return String.valueOf(tempChar);
    }

    /**
     * 将二进制字符串格式化成全16位带空格的Binstr
     *
     * @param input
     * @return
     */
    private String binstrToBinstr16(String input) {
        StringBuilder output = new StringBuilder();
        String[] tempStr = strToStrArray(input);
        for (String aTempStr : tempStr) {
            for (int j = 16 - aTempStr.length(); j > 0; j--) {
                output.append('0');
            }
            output.append(aTempStr).append(" ");
        }
        return output.toString();
    }

    /**
     * 将全16位带空格的Binstr转化成去0前缀的带空格Binstr
     *
     * @param input
     * @return
     */
    private String binstr16ToBinstr(String input) {
        StringBuilder output = new StringBuilder();
        String[] tempStr = strToStrArray(input);
        for (String aTempStr : tempStr) {
            for (int j = 0; j < 16; j++) {
                if (aTempStr.charAt(j) == '1') {
                    output.append(aTempStr.substring(j)).append(" ");
                    break;
                }
                if (j == 15 && aTempStr.charAt(j) == '0') {
                    output.append("0" + " ");
                }
            }
        }
        return output.toString();
    }

    /**
     * 二进制字串转化为boolean型数组 输入16位有空格的Binstr
     *
     * @param input
     * @return
     */
    private boolean[] binstr16ToBool(String input) {
        String[] tempStr = strToStrArray(input);
        boolean[] output = new boolean[tempStr.length * 16];
        for (int i = 0, j = 0; i < input.length(); i++, j++) {
            if (input.charAt(i) == '1') {
                output[j] = true;
            } else if (input.charAt(i) == '0') {
                output[j] = false;
            } else {
                j--;
            }

        }

        return output;
    }

    /**
     * boolean型数组转化为二进制字串 返回带0前缀16位有空格的Binstr
     *
     * @param input
     * @return
     */
    private String boolToBinstr16(boolean[] input) {
        StringBuilder output = new StringBuilder();
        for (int i = 0; i < input.length; i++) {
            if (input[i]) {
                output.append('1');
            } else {
                output.append('0');
            }
            if ((i + 1) % 16 == 0) {
                output.append(' ');
            }
        }
        output.append(' ');
        return output.toString();
    }

    /**
     * 将二进制字符串转换为char
     *
     * @param binStr
     * @return
     */
    private char binstrToChar(String binStr) {
        int[] temp = binstrToIntArray(binStr);
        int sum = 0;
        for (int i = 0; i < temp.length; i++) {
            sum += temp[temp.length - 1 - i] << i;
        }
        return (char) sum;
    }

    /**
     * 将初始二进制字符串转换成字符串数组，以空格相隔
     *
     * @param str
     * @return
     */
    private String[] strToStrArray(String str) {
        return str.split(" ");
    }

    /**
     * 将二进制字符串转换成int数组
     *
     * @param binStr
     * @return
     */
    private int[] binstrToIntArray(String binStr) {
        char[] temp = binStr.toCharArray();
        int[] result = new int[temp.length];
        for (int i = 0; i < temp.length; i++) {
            result[i] = temp[i] - 48;
        }
        return result;
    }

    /**
     * 字符串转二进制
     *
     * @param str
     * @return
     */
    public static byte[] hex2byte(String str) {
        if (str == null) {
            return null;
        }

        str = str.trim();
        int len = str.length();

        if (len == 0 || len % 2 == 1) {
            return null;
        }

        byte[] b = new byte[len / 2];
        try {
            for (int i = 0; i < str.length(); i += 2) {
                b[i / 2] = (byte) Integer
                        .decode("0X" + str.substring(i, i + 2)).intValue();
            }
            return b;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 二进制转字符串
     *
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b) {
        StringBuilder sb = new StringBuilder();
        String tmp = "";
        for (byte aB : b) {
            tmp = Integer.toHexString(aB & 0XFF);
            if (tmp.length() == 1) {
                sb.append("0").append(tmp);
            } else {
                sb.append(tmp);
            }

        }
        return sb.toString();
    }

    /**
     * 把一个字符串专程boolean
     *
     * @param string
     * @return
     */
    public static boolean toBoolean(String string) {

        try {
            return Boolean.parseBoolean(string);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("非法参数");
        }

    }

    /**
     * 把一个字符串专程整型
     *
     * @param string
     * @return
     * @throws Exception
     */
    public static Integer toInt(String string) {
        try {
            return Integer.parseInt(string);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("非法字符");
        }
    }

    /**
     * 格式化邮箱名字
     *
     * @param str
     * @return
     */
    public static String[] toStringArray(String str) {
        if (StringUtils.isNotBlank(str)) {
            str = str.replace(";", " ").replace(",", " ");
            return str.split(" ");
        }
        return new String[]{};
    }


    /**
     * 整数查找
     *
     * @param arr
     * @param target
     * @return
     */
    public static int find(int[] arr, int target) {
        int mid = arr.length / 2;
        int start = 0;
        int end = arr.length - 1;

        while (start < mid && mid < end) {
            if (arr[mid] > target) {
                end = mid;
            } else if (arr[mid] < target) {
                start = mid;
            } else {
                return mid;
            }
            mid = (start + end) / 2;

        }
        return -1;

        // int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        // System.out.println(find(arr, 2));
    }

    /**
     * 获取时间戳
     *
     * @return
     */
    public static int getTime() {
        return Long.valueOf(getMillis() / 1000).intValue();
    }


    public static long getMillis() {
        return System.currentTimeMillis();
    }


    /**
     * 吧list string类型转成int
     *
     * @param strings
     * @return
     */
    public static List<Integer> listStringToInt(List<String> strings) {
        List<Integer> integers = new ArrayList<>();
        for (String string : strings) {
            integers.add(Integer.valueOf(string));
        }
        return integers;
    }

    /**
     * @param id
     * @param split
     * @return
     */
    public static List<Integer> toList(String id, String split) {
        if (StringUtils.isEmpty(id)) {
            return Collections.emptyList();
        }
        List<Integer> integers = new ArrayList<>();
        if (!id.contains(split)) {
            integers.add(Integer.valueOf(id));
            return integers;
        }

        String[] a = id.split(split);

        for (String string : a) {
            integers.add(Integer.valueOf(string));
        }
        return integers;
    }

    /**
     * byte[] 合并
     *
     * @param byte_1
     * @param byte_2
     * @return
     */
    public static byte[] byteMerger(byte[] byte_1, byte[] byte_2) {
        byte[] byte_3 = new byte[byte_1.length + byte_2.length];
        System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
        System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
        return byte_3;
    }

    /**
     * 数据合并
     *
     * @param first
     * @param rest
     * @param <T>
     * @return
     */
    public static <T> T[] concat(T[] first, T[]... rest) {
        int totalLength = first.length;
        for (T[] array : rest) {
            totalLength += array.length;
        }
        T[] result = Arrays.copyOf(first, totalLength);
        int offset = first.length;
        for (T[] array : rest) {
            System.arraycopy(array, 0, result, offset, array.length);
            offset += array.length;
        }
        return result;
    }

    public static String getLength(String str, int length) {
        StringBuilder sb = new StringBuilder();
        //不够9位0补齐
        for (int i = 0; i < length - str.length(); i++) {
            sb.append("0");
        }
        sb.append(str);
        return sb.toString();
    }

    /**
     * 获取一时间位准的流水号 供21位
     *
     * @return
     */
    public static String getSerialNumber() {
        Clock clock = Clock.system(ZoneId.of("Asia/Shanghai"));
        LocalDateTime localTime = LocalDateTime.now(clock);
        String timeCode = localTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
        Random random = new Random();
        double d = random.nextDouble();
        DecimalFormat decimalFormat = new DecimalFormat("#");
        d += 1;
        d *= 100;
        String dd = decimalFormat.format(d);
        return timeCode + getLength(dd, 4);
    }

    /**
     * ByteBuffer - string 转换
     *
     * @param str
     * @return
     */
    public static ByteBuffer parseStringAtByteBuffer(String str) {
        return ByteBuffer.wrap(str.getBytes());
    }

    public static String parseByteBufferAtString(ByteBuffer buffer) {

        Charset charset = null;
        CharsetDecoder decoder = null;
        CharBuffer charBuffer = null;
        try {
            charset = Charset.forName("UTF-8");
            decoder = charset.newDecoder();
            //用这个的话，只能输出来一次结果，第二次显示为空
            // charBuffer = decoder.decode(buffer);
            charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
            return charBuffer.toString();
        } catch (Exception ex) {
            ex.printStackTrace();
            return "error";
        }
    }
}